﻿using RPCServer.Attributes;
using RPCServer.Struct;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RPCServer.Network
{
    /// <summary>
    /// 接收StreamData
    /// 通过属性获取所有协议解析者
    /// 将StreamData解析，分派给不同协议解析者处理
    /// 协议解析者含有静态方法Decode和Encode
    /// </summary>
    class ProtocolParser
    {
        public const string EncodeTag = "Encode";
        public const string DecodeTag = "Decode";

        static readonly Dictionary<int, Func<object, DataBuffer>> _encodes = new();
        static readonly Dictionary<int, Func<DataBuffer, object>> _decodes = new();

        static bool isLoad = false;

        public static void Load(System.Reflection.Assembly assembly)
        {
            foreach (var type in CommolOption.GetTypesWhitAttribute<ProtocolAttribute>(assembly))
            {
                ProtocolAttribute attribute = CommolOption.GetAttribute<ProtocolAttribute>(type);

                if (CommolOption.TryCreateDelegate(type, EncodeTag, out Func<object, DataBuffer> encode) &&
                    CommolOption.TryCreateDelegate(type, DecodeTag, out Func<DataBuffer, object> decode))
                {
                    _decodes.Add(attribute.ID, decode);
                    _encodes.Add(attribute.ID, encode);

                    Console.WriteLine($"==== 协议：{attribute.Tag}");
                }
            }
            isLoad = true;
        }

        public static DataBuffer Encode(object obj)
        {
            if (!isLoad) throw new Exception("ProtocolParser Havn't Load!!!");

            return _encodes[CommolOption.GetAttribute<ProtocolAttribute>(obj.GetType()).ID].Invoke(obj);
        }

        public static object Decode(DataBuffer data)
        {
            if (!isLoad) throw new Exception("ProtocolParser Havn't Load!!!");

            if (data.TryReadInt32(out int type))
            {
                return _decodes[type]?.Invoke(data);
            }

            throw new Exception("=== Decode Type Fail!");
        }
    }
}
